/*
 * @file chip_adc.h
 * @author suyong_yq@126.com
 *
 * @brief LPC8xx ADC driver
 * @note
 * 基于LPCOpen中adc_8xx驱动程序改写
 */

#ifndef __ADC_8XX_H_
#define __ADC_8XX_H_

#include "chip.h"

/* 定义转换队列在ADC驱动代码中的编号 */
#define ADC_CONV_SEQ_IDX_A   0U
#define ADC_CONV_SEQ_IDX_B   1U

/*!
 * @brief ADC转换队列触发源
 */
typedef enum
{
    eADC_TriggerBySoftTriggerOnly = 0U, /*!< 软件触发，写START寄存器位触发转换 */
    eADC_TriggerByAdcTriggerPin0  = 1U, /*!< 硬件触发，触发信号通过SWM连接到外部引脚 */
    eADC_TriggerByAdcTriggerPin1  = 2U, /*!< 硬件触发，触发信号通过SWM连接到外部引脚 */
    eADC_TriggerBySCT0Out3        = 3U, /*!< 硬件触发，SCT0的OUT3通道 */
    eADC_TriggerByAcmpOutput      = 4U, /*!< 硬件触发，ACMP模块的输出 */
    eADC_TriggerByArmTxev         = 5U, /*!< 硬件触发，ARM内核的TXEV事件 */
} ADC_Trigger_T;

/*!
 * @brief 输入触发信号极性
 */
typedef enum
{
    eADC_TriggerInputPolOnNegativeEdge = 0U, /*!< 下降沿触发 */
    eADC_TriggerInputPolOnPositiveEdge = 1U, /*!< 上升沿触发 */
} ADC_TriggerInputPolarity_T;

/*!
 * @brief 指定转换队列的优先级
 *
 * 当两个转换队列需要同时工作时，唯一的一个转换器只能服务其中一个转换队列，此时
 * 优先级高的转换队列将获得对转换器的使用权。
 */
typedef enum
{
    eADC_ConvSeqPriorityLow  = 0U, /*!< 低优先级 */
    eADC_ConvSeqPriorityHigh = 1U, /*!< 高优先级 */
} ADC_ConvSeqPriority_T;

/*!
 * @brief 制定转换队列产生中断的时机
 */
typedef enum
{
    eADC_ConvSeqInterruptOnEndOfConvsersion = 0U, /*!< 在每个转换之后产生中断 */
    eADC_ConvSeqInterruptOnEndOfSequence    = 1U, /*!< 在完整的转换队列之后产生中断 */
} ADC_ConvSeqInterruptMode_T;

/*!
 * 配置转换队列属性
 */
typedef struct
{
    /* 从低到高表示包含每一个转换通道，当触发信号到来之时，从低到高开始转换 */
    uint32_t                   ChannelMaskValue;     /*!< 转换队列中包含的转换通道 */
    ADC_Trigger_T              Trigger;              /*!< 触发源 */
    ADC_TriggerInputPolarity_T TriggerInputPolarity;
    bool                       EnableHwTriggerSyncBypass; /*!< 启用异步触发模式 */
    bool                       EnableSingleStepMode; /*!< 单步转换模式 */
    ADC_ConvSeqPriority_T      Priority;             /*!< 当两个队列被同时触发是使用的优先级 */
    ADC_ConvSeqInterruptMode_T InterruptMode;        /*!< 触发中断的时机 */
} ADC_SeqConfig_T;

/*!
* @brief 转换结果与阈值寄存器比较状态标志
*/
typedef enum
{
    eADC_ConvResultCompareLow    = 0U, /*!< 转换结果低于低阈值 */
    eADC_ConvResultCompareMiddle = 1U, /*!< 转换结果介于低阈值和高阈值之间 */
    eADC_ConvResultCompareHigh   = 2U, /*!< 转换结果高于高阈值 */
} ADC_ConvResultCompareMode_T;

/*!
* @brief 转换结果阈值过零事件状态标志
*/
typedef enum
{
    eADC_ConvResultCrossingNoEvent0    = 0x0, /*!< 没有阈值过零事件发生 */
    eADC_ConvResultCrossingNoEvent1    = 0x1, /*!< 没有阈值过零事件发生 */
    eADC_ConvResultCrossingFallingEdge = 0x2, /*!< 有阈值过零事件，为下降沿 */
    eADC_ConvResultCrossingRisingEdge  = 0x3, /*!< 有阈值过零事件，为上升沿 */
} ADC_ConvResultCrossingMode_T;

/*!
 * @brief 保存转换结果信息
 */
typedef struct
{
    uint32_t                     Result;        /*!< 转换结果值 */
    ADC_ConvResultCompareMode_T  CompareMode;   /*!< 硬件比较的结果 */
    ADC_ConvResultCrossingMode_T CrossingMode;  /*!< 过零检测的结果 */
    uint32_t                     ChannelIdx;    /*!< 最后一次转换的通道号 */
    bool                         OnOverrun;     /*!< 是否溢出，未读走上次数据就执行下次转换，前一次转换结果丢失 */
    bool                         OnDataAvailable; /*!< 数据是否有效 */
} ADC_ResultInfo_T;

#define CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(x)  (0x1 << (3 + (x)))
#define CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(x)  (0x2 << (3 + (x)))

enum ADC_InterruptEnable_T
{
    eADC_InterruptOnSeqA = (1U << 0),
    eADC_InterruptOnSeqB = (1U << 1),
    eADC_InterruptOnOverrun = (1U << 2),
    eADC_InterruptOnHwCompare0OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(0),
    eADC_InterruptOnHwCompare0CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(0),
    eADC_InterruptOnHwCompare1OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(1),
    eADC_InterruptOnHwCompare1CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(1),
    eADC_InterruptOnHwCompare2OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(2),
    eADC_InterruptOnHwCompare2CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(2),
    eADC_InterruptOnHwCompare3OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(3),
    eADC_InterruptOnHwCompare3CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(3),
    eADC_InterruptOnHwCompare4OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(4),
    eADC_InterruptOnHwCompare4CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(4),
    eADC_InterruptOnHwCompare5OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(5),
    eADC_InterruptOnHwCompare5CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(5),
    eADC_InterruptOnHwCompare6OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(6),
    eADC_InterruptOnHwCompare6CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(6),
    eADC_InterruptOnHwCompare7OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(7),
    eADC_InterruptOnHwCompare7CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(7),
    eADC_InterruptOnHwCompare8OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(8),
    eADC_InterruptOnHwCompare8CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(8),
    eADC_InterruptOnHwCompare9OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(9),
    eADC_InterruptOnHwCompare9CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(9),
    eADC_InterruptOnHwCompare10OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(10),
    eADC_InterruptOnHwCompare10CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(10),
    eADC_InterruptOnHwCompare11OutsideThreshold = CHIP_ADC_INTERRUPT_ON_HW_COMPARE_OUTSIDE_THRESHOLD(11),
    eADC_InterruptOnHwCompare11CrossingThreshold= CHIP_ADC_INTERRUPT_ON_HW_COMPARE_CROSSING_THRESHOLD(11),
    /* eADC_InterruptAll = 0xFFFFFFFF, */
};
#define eADC_InterruptAll 0xFFFFFFFF


#define CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(chnIdx) (0x1 << (chnIdx))
#define CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(chnIdx) (0x1 << ((chnIdx) + 12))
#define CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CONV_SEQ(seqIdx) (0x1 << ((seqIdx) + 24))
#define CHIP_ADC_STATUS_FLAG_OF_INTERRUPT_CONV_SEQ(seqIdx) (0x1 << ((seqIdx) + 28))

enum ADC_StatusFlags_T
{
    eADC_StatusFlagOfThresholdCompareEventChn0  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(0),
    eADC_StatusFlagOfThresholdCompareEventChn1  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(1),
    eADC_StatusFlagOfThresholdCompareEventChn2  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(2),
    eADC_StatusFlagOfThresholdCompareEventChn3  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(3),
    eADC_StatusFlagOfThresholdCompareEventChn4  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(4),
    eADC_StatusFlagOfThresholdCompareEventChn5  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(5),
    eADC_StatusFlagOfThresholdCompareEventChn6  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(6),
    eADC_StatusFlagOfThresholdCompareEventChn7  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(7),
    eADC_StatusFlagOfThresholdCompareEventChn8  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(8),
    eADC_StatusFlagOfThresholdCompareEventChn9  = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(9),
    eADC_StatusFlagOfThresholdCompareEventChn10 = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(10),
    eADC_StatusFlagOfThresholdCompareEventChn11 = CHIP_ADC_STATUS_FLAG_OF_THCMP_CHN(11),

    eADC_StatusFlagOfOverrunOnChn0  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(0),
    eADC_StatusFlagOfOverrunOnChn1  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(1),
    eADC_StatusFlagOfOverrunOnChn2  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(2),
    eADC_StatusFlagOfOverrunOnChn3  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(3),
    eADC_StatusFlagOfOverrunOnChn4  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(4),
    eADC_StatusFlagOfOverrunOnChn5  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(5),
    eADC_StatusFlagOfOverrunOnChn6  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(6),
    eADC_StatusFlagOfOverrunOnChn7  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(7),
    eADC_StatusFlagOfOverrunOnChn8  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(8),
    eADC_StatusFlagOfOverrunOnChn9  = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(9),
    eADC_StatusFlagOfOverrunOnChn10 = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(10),
    eADC_StatusFlagOfOverrunOnChn11 = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CHN(11),

    eADC_StatusFlagOfOverrunOnConvSeqA = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CONV_SEQ(0),
    eADC_StatusFlagOfOverrunOnConvSeqB = CHIP_ADC_STATUS_FLAG_OF_OVERRUN_CONV_SEQ(1),

    eADC_StatusFlagOfInterruptOnConvSeqA = CHIP_ADC_STATUS_FLAG_OF_INTERRUPT_CONV_SEQ(0),
    eADC_StatusFlagOfInterruptOnConvSeqB = CHIP_ADC_STATUS_FLAG_OF_INTERRUPT_CONV_SEQ(1),

    eADC_StatusFlagOfThresholdCompareEventChnAny = (1U << 30),
    /* eADC_StatusFlagOfOverrunOnChnAny = (1U << 31), */
};
/* enum is based on the int type, so create this specifical item to ignore the warning */
#define eADC_StatusFlagOfOverrunOnChnAny (1U << 31)

#ifdef __cplusplus
extern "C" {
#endif

/* Converter. */
void Chip_ADC_SetConvClkDiv(LPC_ADC_T *base, uint8_t divVal);
void Chip_ADC_DoHwSelfCalibratioin(LPC_ADC_T *base, uint8_t divVal); /* 设定ADC Clock工作在约500kHz */
    
/* Conv Sequence. */
void Chip_ADC_EnableConvSeq(LPC_ADC_T *base, uint32_t seqIdx, bool enable);
void Chip_ADC_DoConvSeqSoftTrigger(LPC_ADC_T *base, uint32_t seqIdx);
void Chip_ADC_EnableConvSeqBurst(LPC_ADC_T *base, uint32_t seqIdx, bool enable);
void Chip_ADC_ConfigConvSeq(LPC_ADC_T *base, uint32_t seqIdx, const ADC_SeqConfig_T *config);
void Chip_ADC_GetConvSeqGlobalResult(LPC_ADC_T *base, uint32_t seqIdx, ADC_ResultInfo_T *info);

/* Channel Data. */
void Chip_ADC_GetConvChannelResult(LPC_ADC_T *base, uint32_t chnIdx, ADC_ResultInfo_T *info);

/* Hardware Compare. */
void Chip_ADC_SetHwCompareThreshold(LPC_ADC_T *base, uint32_t groupIdx, uint32_t low, uint32_t high);
void Chip_ADC_EnableHwCompareChannel(LPC_ADC_T *base, uint32_t groupIdx, uint32_t chnMask);

/* Events & Flags. */
void Chip_ADC_EnableInterrupt(LPC_ADC_T *base, uint32_t intMask); /* enum ADC_InterruptEnable_T */
void Chip_ADC_DisableInterrupt(LPC_ADC_T *base, uint32_t intMask); /* enum ADC_InterruptEnable_T */
uint32_t Chip_ADC_GetStatusFlags(LPC_ADC_T *base); /* enum ADC_StatusFlags_T */
void Chip_ADC_ClearStatusFlags(LPC_ADC_T *base, uint32_t flagMask); /* enum ADC_StatusFlags_T */

#ifdef __cplusplus
}
#endif

#endif /* __ADC_8XX_H_ */
